home *** CD-ROM | disk | FTP | other *** search
/ Visual Basic Graphics Programming (2nd Edition) / Visual Basic Graphics Programming 2nd Edition.iso / OldSrc / CH11 / SRC / OBJPLIN3.CLS < prev    next >
Text File  |  1996-05-04  |  13KB  |  487 lines

  1. VERSION 1.0 CLASS
  2. BEGIN
  3.   MultiUse = -1  'True
  4. END
  5. Attribute VB_Name = "ObjPolyline"
  6. Attribute VB_Creatable = False
  7. Attribute VB_Exposed = False
  8. Option Explicit
  9.  
  10. ' Point3D and Segment3D are defined in module M3OPS.BAS as:
  11. '    Type Point3D
  12. '        coord(1 To 4) As Single
  13. '        trans(1 To 4) As Single
  14. '    End Type
  15. '
  16. '    Type Segment3D
  17. '        pt1 As Integer
  18. '        pt2 As Integer
  19. '    End Type
  20.  
  21. Private NumPoints As Integer ' Number of points.
  22. Private Points() As Point3D  ' Data points.
  23.  
  24. Private NumSegs As Integer   ' Number of segments.
  25. Private Segs() As Segment3D  ' The segments.
  26.  
  27. Private IsCulled As Boolean
  28.  
  29. ' ***********************************************
  30. ' This is done at drawing time for polylines.
  31. ' ***********************************************
  32. Public Sub ClipEye(r As Single)
  33. End Sub
  34.  
  35. ' ************************************************
  36. ' Draw the transformed points on a Form, Printer,
  37. ' or PictureBox using API functions.
  38. ' ************************************************
  39. Public Sub DrawOrdered(canvas As Object, Optional r As Variant)
  40. Dim seg As Integer
  41. Dim pt1 As Integer
  42. Dim pt2 As Integer
  43. Dim dist As Single
  44. Dim status As Long
  45.  
  46.     ' Don't draw if culled.
  47.     If IsCulled Then Exit Sub
  48.     
  49.     On Error Resume Next
  50.     If IsMissing(r) Then r = INFINITY
  51.     dist = r
  52.     For seg = 1 To NumSegs
  53.         pt1 = Segs(seg).pt1
  54.         pt2 = Segs(seg).pt2
  55.         ' Don't draw if either point is farther
  56.         ' from the focus point than the center of
  57.         ' projection (which is distance dist away).
  58.         If Points(pt1).trans(3) < dist And _
  59.            Points(pt2).trans(3) < dist Then
  60.                 #If Win32 Then
  61.                     status = API_MoveTo(canvas.hdc, _
  62.                         Points(pt1).trans(1), _
  63.                         Points(pt1).trans(2), 0&)
  64.                 #Else
  65.                     status = API_MoveTo(canvas.hdc, _
  66.                         Points(pt1).trans(1), _
  67.                         Points(pt1).trans(2))
  68.                 #End If
  69.                 status = API_LineTo(canvas.hdc, _
  70.                     Points(pt2).trans(1), _
  71.                     Points(pt2).trans(2))
  72.         End If
  73.     Next seg
  74. End Sub
  75.  
  76. ' ***********************************************
  77. ' Return the maximum transformed Z value for this
  78. ' object.
  79. ' ***********************************************
  80. Property Get zmax() As Single
  81. Dim best As Single
  82. Dim z As Single
  83. Dim i As Integer
  84.  
  85.     best = Points(1).trans(3)
  86.     For i = 2 To NumPoints
  87.         z = Points(i).trans(3)
  88.         If best < z Then best = z
  89.     Next i
  90.     zmax = best
  91. End Property
  92.  
  93.  
  94.  
  95. Sub Stellate(L As Single, ParamArray coord() As Variant)
  96. Dim x0 As Single
  97. Dim y0 As Single
  98. Dim z0 As Single
  99. Dim x1 As Single
  100. Dim y1 As Single
  101. Dim z1 As Single
  102. Dim x2 As Single
  103. Dim y2 As Single
  104. Dim z2 As Single
  105. Dim x3 As Single
  106. Dim y3 As Single
  107. Dim z3 As Single
  108. Dim Ax As Single
  109. Dim Ay As Single
  110. Dim Az As Single
  111. Dim Bx As Single
  112. Dim By As Single
  113. Dim Bz As Single
  114. Dim nx As Single
  115. Dim ny As Single
  116. Dim nz As Single
  117. Dim num As Integer
  118. Dim i As Integer
  119. Dim pt As Integer
  120.  
  121.     num = (UBound(coord) + 1) \ 3
  122.     If num < 3 Then
  123.         Beep
  124.         MsgBox "Must have at least 3 points to stellate.", , vbExclamation
  125.         Exit Sub
  126.     End If
  127.     
  128.     ' (x0, y0, z0) is the center of the polygon.
  129.     x0 = 0
  130.     y0 = 0
  131.     z0 = 0
  132.     pt = 0
  133.     For i = 1 To num
  134.         x0 = x0 + coord(pt)
  135.         y0 = y0 + coord(pt + 1)
  136.         z0 = z0 + coord(pt + 2)
  137.         pt = pt + 3
  138.     Next i
  139.     x0 = x0 / num
  140.     y0 = y0 / num
  141.     z0 = z0 / num
  142.     
  143.     ' Find the normal.
  144.     x1 = coord(0)
  145.     y1 = coord(1)
  146.     z1 = coord(2)
  147.     x2 = coord(3)
  148.     y2 = coord(4)
  149.     z2 = coord(5)
  150.     x3 = coord(6)
  151.     y3 = coord(7)
  152.     z3 = coord(8)
  153.     Ax = x2 - x1
  154.     Ay = y2 - y1
  155.     Az = z2 - z1
  156.     Bx = x3 - x2
  157.     By = y3 - y2
  158.     Bz = z3 - z2
  159.     m3Cross nx, ny, nz, Ax, Ay, Az, Bx, By, Bz
  160.     
  161.     ' Give the normal length L.
  162.     m3SizeVector L, nx, ny, nz
  163.     
  164.     ' The normal + <x0, y0, z0> gives the point.
  165.     x0 = x0 + nx
  166.     y0 = y0 + ny
  167.     z0 = z0 + nz
  168.  
  169.     ' Build the segments that make up the object.
  170.     x1 = coord(3 * num - 3)
  171.     y1 = coord(3 * num - 2)
  172.     z1 = coord(3 * num - 1)
  173.     pt = 0
  174.     For i = 1 To num
  175.         x2 = coord(pt)
  176.         y2 = coord(pt + 1)
  177.         z2 = coord(pt + 2)
  178.         AddSegment x1, y1, z1, x2, y2, z2, x0, y0, z0
  179.         x1 = x2
  180.         y1 = y2
  181.         z1 = z2
  182.         pt = pt + 3
  183.     Next i
  184. End Sub
  185.  
  186. Sub CreateNormal(Objects As Collection)
  187. Dim pline As New ObjPolyline
  188. Dim x1 As Single
  189. Dim y1 As Single
  190. Dim z1 As Single
  191. Dim x2 As Single
  192. Dim y2 As Single
  193. Dim z2 As Single
  194.  
  195.     Objects.Add pline
  196.     UnitNormalSegment x1, y1, z1, x2, y2, z2
  197.     pline.AddSegment x1, y1, z1, x2, y2, z2
  198. End Sub
  199.  
  200.  
  201. ' ***********************************************
  202. ' Compute a normal vector for this polyline.
  203. ' ***********************************************
  204. Sub NormalVector(nx As Single, ny As Single, nz As Single)
  205. Dim Ax As Single
  206. Dim Ay As Single
  207. Dim Az As Single
  208. Dim Bx As Single
  209. Dim By As Single
  210. Dim Bz As Single
  211.  
  212.     Ax = Points(2).coord(1) - Points(1).coord(1)
  213.     Ay = Points(2).coord(2) - Points(1).coord(2)
  214.     Az = Points(2).coord(3) - Points(1).coord(3)
  215.     Bx = Points(3).coord(1) - Points(2).coord(1)
  216.     By = Points(3).coord(2) - Points(2).coord(2)
  217.     Bz = Points(3).coord(3) - Points(2).coord(3)
  218.     m3Cross nx, ny, nz, Ax, Ay, Az, Bx, By, Bz
  219. End Sub
  220.  
  221.  
  222.  
  223. ' ***********************************************
  224. ' Compute the unit normal line segment for this
  225. ' polyline.
  226. ' ***********************************************
  227. Sub UnitNormalSegment(x1 As Single, y1 As Single, z1 As Single, x2 As Single, y2 As Single, z2 As Single)
  228. Dim i As Integer
  229. Dim nx As Single
  230. Dim ny As Single
  231. Dim nz As Single
  232.     
  233.     UnitNormalVector nx, ny, nz
  234.     
  235.     x1 = 0
  236.     y1 = 0
  237.     z1 = 0
  238.     For i = 1 To NumPoints
  239.         x1 = x1 + Points(i).coord(1)
  240.         y1 = y1 + Points(i).coord(2)
  241.         z1 = z1 + Points(i).coord(3)
  242.     Next i
  243.     x1 = x1 / NumPoints
  244.     y1 = y1 / NumPoints
  245.     z1 = z1 / NumPoints
  246.  
  247.     x2 = x1 + nx
  248.     y2 = y1 + ny
  249.     z2 = z1 + nz
  250. End Sub
  251.  
  252.  
  253. ' ***********************************************
  254. ' Compute the unit normal vector for this
  255. ' polyline.
  256. ' ***********************************************
  257. Sub UnitNormalVector(nx As Single, ny As Single, nz As Single)
  258. Dim D As Single
  259.  
  260.     NormalVector nx, ny, nz
  261.     D = Sqr(nx * nx + ny * ny + nz * nz)
  262.     nx = nx / D
  263.     ny = ny / D
  264.     nz = nz / D
  265. End Sub
  266.  
  267.  
  268.  
  269.  
  270.  
  271. Property Let Culled(value As Boolean)
  272.     IsCulled = value
  273. End Property
  274.  
  275.  
  276. ' ***********************************************
  277. ' Return a string indicating the object type.
  278. ' ***********************************************
  279. Property Get ObjectType() As String
  280.     ObjectType = "POLYLINE"
  281. End Property
  282.  
  283. ' ************************************************
  284. ' Add one or more line segments to the polyline.
  285. ' ************************************************
  286. Public Sub AddSegment(ParamArray coord() As Variant)
  287. Dim num_segs As Integer
  288. Dim i As Integer
  289. Dim last As Integer
  290. Dim pt As Integer
  291.  
  292.     num_segs = (UBound(coord) + 1) \ 3 - 1
  293.     ReDim Preserve Segs(1 To NumSegs + num_segs)
  294.  
  295.     last = AddPoint((coord(0)), (coord(1)), (coord(2)))
  296.     pt = 0
  297.     For i = 1 To num_segs
  298.         Segs(NumSegs + i).pt1 = last
  299.         pt = pt + 3
  300.         last = AddPoint((coord(pt)), (coord(pt + 1)), (coord(pt + 2)))
  301.         Segs(NumSegs + i).pt2 = last
  302.     Next i
  303.  
  304.     NumSegs = NumSegs + num_segs
  305. End Sub
  306.  
  307. ' ************************************************
  308. ' Add a point to the polyline. Return the point's
  309. ' index.
  310. ' ************************************************
  311. Private Function AddPoint(x As Single, Y As Single, z As Single) As Integer
  312. Dim i As Integer
  313.  
  314.     ' See if the point is already here.
  315.     For i = 1 To NumPoints
  316.         If x = Points(i).coord(1) And _
  317.            Y = Points(i).coord(2) And _
  318.            z = Points(i).coord(3) Then _
  319.                 Exit For
  320.     Next i
  321.     AddPoint = i
  322.     
  323.     ' If so, we're done.
  324.     If i <= NumPoints Then Exit Function
  325.     
  326.     ' Otherwise create the new point.
  327.     NumPoints = NumPoints + 1
  328.     ReDim Preserve Points(1 To NumPoints)
  329.     Points(i).coord(1) = x
  330.     Points(i).coord(2) = Y
  331.     Points(i).coord(3) = z
  332.     Points(i).coord(4) = 1#
  333. End Function
  334.  
  335.  
  336.  
  337. ' ***********************************************
  338. ' Fix the data coordinates at their transformed
  339. ' values.
  340. ' ***********************************************
  341. Public Sub FixPoints()
  342. Dim i As Integer
  343. Dim j As Integer
  344.  
  345.     For i = 1 To NumPoints
  346.         For j = 1 To 3
  347.             Points(i).coord(j) = Points(i).trans(j)
  348.         Next j
  349.     Next i
  350. End Sub
  351.  
  352. ' ************************************************
  353. ' Apply a transformation matrix which may not
  354. ' contain 0, 0, 0, 1 in the last column to the
  355. ' object.
  356. ' ************************************************
  357. Public Sub ApplyFull(M() As Single)
  358. Dim i As Integer
  359.  
  360.     If IsCulled Then Exit Sub
  361.     For i = 1 To NumPoints
  362.         m3ApplyFull Points(i).coord, M, Points(i).trans
  363.     Next i
  364. End Sub
  365.  
  366. ' ************************************************
  367. ' Apply a transformation matrix to the object.
  368. ' ************************************************
  369. Public Sub Apply(M() As Single)
  370. Dim i As Integer
  371.  
  372.     If IsCulled Then Exit Sub
  373.     For i = 1 To NumPoints
  374.         m3Apply Points(i).coord, M, Points(i).trans
  375.     Next i
  376. End Sub
  377.  
  378.  
  379. ' ************************************************
  380. ' Apply a nonlinear transformation.
  381. ' ************************************************
  382. Public Sub Distort(D As Object)
  383. Dim i As Integer
  384.  
  385.     For i = 1 To NumPoints
  386.         D.Distort Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  387.     Next i
  388. End Sub
  389.  
  390. ' ************************************************
  391. ' Write a polyline to a file using Write.
  392. ' Begin with "POLYLINE" to identify this object.
  393. ' ************************************************
  394. Public Sub FileWrite(filenum As Integer)
  395. Dim i As Integer
  396.  
  397.     Write #filenum, "POLYLINE", NumPoints, NumSegs
  398.     
  399.     ' Write the points.
  400.     For i = 1 To NumPoints
  401.         Write #filenum, Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  402.     Next i
  403.  
  404.     ' Write the segments.
  405.     For i = 1 To NumSegs
  406.         Write #filenum, Segs(i).pt1, Segs(i).pt2
  407.     Next i
  408. End Sub
  409.  
  410. ' ************************************************
  411. ' Draw the transformed points on a Form, Printer,
  412. ' or PictureBox.
  413. ' ************************************************
  414. Public Sub Draw(canvas As Object, Optional r As Variant)
  415. Dim seg As Integer
  416. Dim pt1 As Integer
  417. Dim pt2 As Integer
  418. Dim dist As Single
  419.  
  420.     ' Don't draw if culled.
  421.     If IsCulled Then Exit Sub
  422.     
  423.     On Error Resume Next
  424.     If IsMissing(r) Then r = INFINITY
  425.     dist = r
  426.     For seg = 1 To NumSegs
  427.         pt1 = Segs(seg).pt1
  428.         pt2 = Segs(seg).pt2
  429.         ' Don't draw if either point is farther
  430.         ' from the focus point than the center of
  431.         ' projection (which is distance dist away).
  432.         If Points(pt1).trans(3) < dist And _
  433.            Points(pt2).trans(3) < dist Then _
  434.                 canvas.Line _
  435.                     (Points(pt1).trans(1), Points(pt1).trans(2))- _
  436.                     (Points(pt2).trans(1), Points(pt2).trans(2))
  437.     Next seg
  438. End Sub
  439. ' ***********************************************
  440. ' Perform backface removal.
  441. ' ***********************************************
  442. Public Sub Cull(x As Single, Y As Single, z As Single)
  443. Dim Ax As Single
  444. Dim Ay As Single
  445. Dim Az As Single
  446. Dim nx As Single
  447. Dim ny As Single
  448. Dim nz As Single
  449.  
  450.     ' Compute a normal to the face.
  451.     NormalVector nx, ny, nz
  452.  
  453.     ' Compute a vector from the center of
  454.     ' projection to the face.
  455.     Ax = Points(1).coord(1) - x
  456.     Ay = Points(1).coord(2) - Y
  457.     Az = Points(1).coord(3) - z
  458.     
  459.     ' See if the vectors meet at an angle < 90.
  460.     IsCulled = (Ax * nx + Ay * ny + Az * nz >= 0)
  461. End Sub
  462. ' ************************************************
  463. ' Read a polyline from a file using Input.
  464. ' Assume the "POLYLINE" label has already been
  465. ' read.
  466. ' ************************************************
  467. Public Sub FileInput(filenum As Integer)
  468. Dim i As Integer
  469.  
  470.     Input #filenum, NumPoints, NumSegs
  471.     
  472.     ' Allocate and read the points.
  473.     ReDim Points(1 To NumPoints)
  474.     For i = 1 To NumPoints
  475.         Input #filenum, Points(i).coord(1), Points(i).coord(2), Points(i).coord(3)
  476.         Points(i).coord(4) = 1
  477.     Next i
  478.     
  479.     ' Allocate and read the segments.
  480.     ReDim Segs(1 To NumSegs)
  481.     For i = 1 To NumSegs
  482.         Input #filenum, Segs(i).pt1, Segs(i).pt2
  483.     Next i
  484. End Sub
  485.  
  486.  
  487.